package dsx.rpcProxy;

import dsx.cache.DsxByteBuffer;
import dsx.inf.IAnswChecker;
import dsx.inf.IConverter;
import dsx.inf.ISlicer;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.ArrayList;

public class TcpClient {
	Object lock = new Object();
	Socket sock = null;
	DsxByteBuffer recvBuf = new DsxByteBuffer(1024, 16777216);

	ArrayList<_TcpConfig> configLst = null;
	int connIndex = 0;

	ISlicer slicer;
	IConverter converter;

	public void start(ArrayList<_TcpConfig> configLst, ISlicer slicer, IConverter converter) throws Exception {
		synchronized (lock) {
			this.configLst = configLst;
			this.connIndex = 0;
			this.slicer = slicer;
			this.converter = converter;
			Connect();
		}
	}

	private void clear() {
		try {
			if (sock != null)
				sock.close();
		} catch (Exception ex) {
		}
		sock = null;
	}

	public void stop() {
		synchronized (lock) {
			clear();
		}
	}

	public Object request(Object reqObj, Class<?> answType) {
		synchronized (lock) {
			try {
				if (sock == null)
					Connect();
				return doRequest(reqObj, answType);
			} catch (Exception ex1) {
				for (int i = 0; i < configLst.size(); i++) {
					try {
						Connect();
						return doRequest(reqObj, answType);
					} catch (Exception ex2) {
					}
				}
			}
			return null;
		}
	}

	private Object doRequest(Object reqObj, Class<?> type) throws Exception {
		// 发送
		byte[] sendData = converter.toBytes(reqObj);
		if (sendData == null)
			return null;
		byte[] sendBuff;
		if (slicer == null)
			sendBuff = sendData;
		else
			sendBuff = slicer.pack(sendData);

		DataOutputStream dos = new DataOutputStream(sock.getOutputStream());
		dos.write(sendBuff);
		dos.flush();
		// 接收
		byte[] recvBytes = new byte[1024];
		DataInputStream dis = new DataInputStream(sock.getInputStream());
		try {
			while (true) {
				int count = dis.read(recvBytes);
				if (count <= 0)
					break;
				for (int i = 0; i < count; i++)
					this.recvBuf.put(recvBytes[i]);
				byte[] answ = slicer.slice(this.recvBuf);
				if (answ != null) {
					Object answObj = converter.toObject(answ, type);
					if (answObj == null) {
						continue;
					} else if (reqObj instanceof IAnswChecker) {
						if (((IAnswChecker) reqObj).checkAnsw(answObj))
							return answObj;
					} else {
						return answObj;
					}
				}
			}
		} catch (Exception ex) {
			System.out.println(ex.getMessage());
			clear();
			throw ex;
		}
//		if (!(reqObj instanceof IAnswChecker))
//			clear();
		return null;
	}

	private void Connect() throws Exception {
		synchronized (lock) {
			clear();
			_TcpConfig config = configLst.get(connIndex);
			connIndex++;
			if (connIndex >= configLst.size())
				connIndex = 0;
			sock = new Socket();
			sock.connect(new InetSocketAddress(config.ip, config.port), config.getTimeout());
			sock.setSoTimeout(config.timeout);
		}
	}

}
